using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;

namespace BepuPhysics.Trees
{
    partial struct Tree
    {
        unsafe void SwapNodes(int indexA, int indexB)
        {
            ref var a = ref Nodes[indexA];
            ref var b = ref Nodes[indexB];
            ref var metaA = ref Metanodes[indexA];
            ref var metaB = ref Metanodes[indexB];

            Helpers.Swap(ref a, ref b);
            Helpers.Swap(ref metaA, ref metaB);

            if (metaA.Parent == indexA)
            {
                // 原来B的父母是A。
                // 那个家长已经搬走了。
                metaA.Parent = indexB;
            }
            else if (metaB.Parent == indexB)
            {
                // 原来A的父母是B。
                // 那个家长已经搬走了。
                metaB.Parent = indexA;
            }
            Unsafe.Add(ref Nodes[metaA.Parent].A, metaA.IndexInParent).Index = indexA;
            Unsafe.Add(ref Nodes[metaB.Parent].A, metaB.IndexInParent).Index = indexB;


            // 更新子对象的父指针。
            ref var children = ref a.A;
            for (int i = 0; i < 2; ++i)
            {
                ref var child = ref Unsafe.Add(ref children, i);
                if (child.Index >= 0)
                {
                    Metanodes[child.Index].Parent = indexA;
                }
                else
                {
                    var leafIndex = Encode(child.Index);
                    Leaves[leafIndex] = new Leaf(indexA, i);
                }
            }
            children = ref b.A;
            for (int i = 0; i < 2; ++i)
            {
                ref var child = ref Unsafe.Add(ref children, i);
                if (child.Index >= 0)
                {
                    Metanodes[child.Index].Parent = indexB;
                }
                else
                {
                    var leafIndex = Encode(child.Index);
                    Leaves[leafIndex] = new Leaf(indexB, i);
                }
            }

        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        unsafe bool TryLock(ref int nodeIndex)
        {
            // 在执行此函数期间,节点索引可能会更改。
            int lockedIndex;
            while (true)
            {
                lockedIndex = nodeIndex;
                if (0 != Interlocked.CompareExchange(ref Metanodes[lockedIndex].RefineFlag, 1, 0))
                {
                    // 中止任务。
                    return false;
                }
                if (lockedIndex != nodeIndex) // 比较交换插入内存屏障。
                {
                    // 锁定了错误的节点,放手。
                    Metanodes[lockedIndex].RefineFlag = 0;
                }
                else
                {
                    // 如果lockedIndex==nodeIndex,并且我们锁定了lockedIndex,那么nodeIndex就不能移动了,我们就完成了。
                    return true;
                }
            }
        }

        unsafe bool TrySwapNodeWithTargetThreadSafe(int swapperIndex, int swapperParentIndex, int swapTargetIndex)
        {
            Debug.Assert(Metanodes[swapperIndex].RefineFlag == 1, "The swapper should be locked.");
            Debug.Assert(Metanodes[swapperParentIndex].RefineFlag == 1, "The swapper parent should be locked.");
            Debug.Assert(swapTargetIndex != swapperIndex, "If the swapper is already at the swap target, this should not be called."); // 比较安全,因为如果相等,则它是锁定的。
            // 我们必须确保节点、其父节点和子节点已锁定。
            // 但是要注意节点之间的父辈或祖辈关系。它们降低了所需的锁数量。

            // 可能的情况如下：
            // 0)掉期对象为掉期者的祖父母。不要锁定==swapper的父级的交换目标的子级。
            // 1)交换目标是交换器的父级。不要锁定交换目标,也不要锁定交换目标的Child==swapper。
            // 2)掉期目标是掉期者的位置(什么都不做,你就完蛋了)。
            // 3)掉期对象为掉期者的子代之一。不要锁定掉期目标,也不要锁定掉期目标的父级。
            // 4)掉期标的是掉期人的孙子之一。不要锁定交换目标的父级。
            // 5)掉期目标与掉期无关。

            // 请注意,我们不必担心重新排序/死锁,因为这些不是阻塞锁。如果其中一个失败,所有锁将立即中止。
            // 这意味着我们不会总是得到最优的缓存布局,但这根本不会影响正确性。
            // 最终,该节点将被重新访问,并且可能会得到修复。

            // 注意迭代TryLock的使用。它接受这样的事实,即在获取锁之前,可以随时改变参考存储器。
            // 它会进行显式检查,以确保它确实在正确的节点上获取了锁。

            // 在以下情况下不要锁定swapTarget：
            // 1)swapTargetIndex==swapperParentIndex,因为swapperParentIndex已经锁定
            // 2)节点[swapTargetIndex].Parent==swapperIndex,因为swapper的子项已经锁定

            // 请注意,可能解锁的节点[swapTargetIndex].Parent和swapperIndex之间的上述比较是安全的,因为
            // 如果它的计算结果为true,则它实际上是锁定的。如果它的计算结果为false,则它们不是同一个节点-可能是哪个随机节点并不重要。
            // 类似的逻辑适用于下面类似的锁省略。

            bool success = false;
            var needSwapTargetLock = swapTargetIndex != swapperParentIndex && Metanodes[swapTargetIndex].Parent != swapperIndex;
            if (!needSwapTargetLock || TryLock(ref swapTargetIndex))
            {
                ref var swapTarget = ref Metanodes[swapTargetIndex];

                // 在以下情况下不要锁定swapTarget->Parent：
                // 1)swapTarget->Parent==swapperIndex,因为swapper已经锁定。
                // 2)节点[swapTarget->Parent].Parent==swapperIndex,因为swapper的子项已经锁定。

                var needSwapTargetParentLock = swapTarget.Parent != swapperIndex && Metanodes[swapTarget.Parent].Parent != swapperIndex;
                if (!needSwapTargetParentLock || TryLock(ref swapTarget.Parent))
                {

                    int childrenLockedCount = 2;
                    ref var children = ref Nodes[swapTargetIndex].A;
                    for (int i = 0; i < 2; ++i)
                    {
                        ref var child = ref Unsafe.Add(ref children, i);
                        // 在以下情况下不要锁定儿童[i]：
                        // 1)子[i]==swapperIndex,因为交换器已经锁定
                        // 2)Child[i]==swapperParentIndex,因为swapperParent已经锁定
                        if (child.Index >= 0 && child.Index != swapperIndex && child.Index != swapperParentIndex && !TryLock(ref child.Index))
                        {
                            // 无法获取对所有子项的锁定。
                            childrenLockedCount = i;
                            break;
                        }
                    }

                    if (childrenLockedCount == 2)
                    {
                        // 节点已成功锁定。
                        SwapNodes(swapperIndex, swapTargetIndex);
                        success = true;

                        // 解锁原始交换目标*的子级,该目标现在位于swapperIndex中*。
                        children = ref Nodes[swapperIndex].A;
                        for (int i = childrenLockedCount - 1; i >= 0; --i)
                        {
                            ref var child = ref Unsafe.Add(ref children, i);
                            // 同样,请注意使用swapTargetIndex而不是swapperIndex。
                            if (child.Index >= 0 && child.Index != swapTargetIndex && child.Index != swapperParentIndex) // 避免解锁调用方已锁定的子项。
                                Metanodes[child.Index].RefineFlag = 0;
                        }
                    }
                    else
                    {
                        // 未进行任何交换。仍然可以使用swapTarget->ChildA指针。
                        for (int i = childrenLockedCount - 1; i >= 0; --i)
                        {
                            ref var child = ref Unsafe.Add(ref children, i);
                            if (child.Index >= 0 && child.Index != swapperIndex && child.Index != swapperParentIndex) // 避免解锁调用方已锁定的子项。
                                Metanodes[child.Index].RefineFlag = 0;
                        }
                    }


                    if (needSwapTargetParentLock)
                    {
                        if (success)
                        {
                            // 请注意,由于节点已交换,因此不再使用swapTarget指针。
                            // 旧的掉期目标现在位于掉期指数槽中！
                            Metanodes[Metanodes[swapperIndex].Parent].RefineFlag = 0;
                        }
                        else
                        {
                            // 未发生交换,
                            Metanodes[swapTarget.Parent].RefineFlag = 0;
                        }
                    }
                }

                if (needSwapTargetLock)
                {
                    if (success)
                    {
                        // 同样,原始的swapTarget现在位于swapperIndex中。
                        Metanodes[swapperIndex].RefineFlag = 0;
                    }
                    else
                    {
                        swapTarget.RefineFlag = 0;
                    }
                }
            }
            return success;
        }


        public unsafe bool TryLockSwapTargetThreadSafe(ref int swapTargetIndex, int swapperIndex, int swapperParentIndex)
        {
            Debug.Assert(Metanodes[swapperIndex].RefineFlag == 1, "The swapper should be locked.");
            Debug.Assert(Metanodes[swapperParentIndex].RefineFlag == 1, "The swapper parent should be locked.");
            Debug.Assert(swapTargetIndex != swapperIndex, "If the swapper is already at the swap target, this should not be called."); // 比较安全,因为如果相等,则它是锁定的。
            // 我们必须确保节点、其父节点和子节点已锁定。
            // 但是要注意节点之间的父辈或祖辈关系。它们降低了所需的锁数量。

            // 可能的情况如下：
            // 0)掉期对象为掉期者的祖父母。不要锁定==swapper的父级的交换目标的子级。
            // 1)交换目标是交换器的父级。不要锁定交换目标,也不要锁定交换目标的Child==swapper。
            // 2)掉期目标是掉期者的位置(什么都不做,你就完蛋了)。
            // 3)掉期对象为掉期者的子代之一。不要锁定掉期目标,也不要锁定掉期目标的父级。
            // 4)掉期标的是掉期人的孙子之一。不要锁定交换目标的父级。
            // 5)掉期目标与掉期无关。

            // 请注意,我们不必担心重新排序/死锁,因为这些不是阻塞锁。如果其中一个失败,所有锁将立即中止。
            // 这意味着我们不会总是得到最优的缓存布局,但这根本不会影响正确性。
            // 最终,该节点将被重新访问,并且可能会得到修复。

            // 注意迭代TryLock的使用。它接受这样的事实,即在获取锁之前,可以随时改变参考存储器。
            // 它会进行显式检查,以确保它确实在正确的节点上获取了锁。

            // 在以下情况下不要锁定swapTarget：
            // 1)swapTargetIndex==swapperParentIndex,因为swapperParentIndex已经锁定
            // 2)节点[swapTargetIndex].Parent==swapperIndex,因为swapper的子项已经锁定

            // 请注意,可能解锁的节点[swapTargetIndex].Parent和swapperIndex之间的上述比较是安全的,因为
            // 如果它的计算结果为true,则它实际上是锁定的。如果它的计算结果为false,则它们不是同一个节点-可能是哪个随机节点并不重要。
            // 类似的逻辑适用于下面类似的锁省略。

            bool success = false;
            var needSwapTargetLock = swapTargetIndex != swapperParentIndex && Metanodes[swapTargetIndex].Parent != swapperIndex;
            if (!needSwapTargetLock || TryLock(ref swapTargetIndex))
            {
                ref var swapTarget = ref Metanodes[swapTargetIndex];

                // 在以下情况下不要锁定swapTarget->Parent：
                // 1)swapTarget->Parent==swapperIndex,因为swapper已经锁定。
                // 2)节点[swapTarget->Parent].Parent==swapperIndex,因为swapper的子项已经锁定。

                var needSwapTargetParentLock = swapTarget.Parent != swapperIndex && Metanodes[swapTarget.Parent].Parent != swapperIndex;
                if (!needSwapTargetParentLock || TryLock(ref swapTarget.Parent))
                {

                    int childrenLockedCount = 2;
                    ref var children = ref Nodes[swapTargetIndex].A;
                    for (int i = 0; i < 2; ++i)
                    {
                        ref var child = ref Unsafe.Add(ref children, i);
                        // 在以下情况下不要锁定儿童[i]：
                        // 1)子[i]==swapperIndex,因为交换器已经锁定
                        // 2)Child[i]==swapperParentIndex,因为swapperParent已经锁定
                        if (child.Index != swapperIndex && child.Index != swapperParentIndex && !TryLock(ref child.Index))
                        {
                            // 无法获取对所有子项的锁定。
                            childrenLockedCount = i;
                            break;
                        }
                    }

                    if (childrenLockedCount == 2)
                    {
                        // 节点已成功锁定。
                        success = true;
                    }
                    // TODO：不应在此处解锁,因为这是一个锁定函数！
                    for (int i = childrenLockedCount - 1; i >= 0; --i)
                    {
                        ref var child = ref Unsafe.Add(ref children, i);
                        if (child.Index != swapperIndex && child.Index != swapperParentIndex) // 避免解锁调用方已锁定的子项。
                            Metanodes[child.Index].RefineFlag = 0;
                    }

                    if (needSwapTargetParentLock)
                        Metanodes[swapTarget.Parent].RefineFlag = 0;
                }
                if (needSwapTargetLock)
                    swapTarget.RefineFlag = 0;
            }
            return success;
        }

        /// <summary>
        /// 尝试交换两个节点。如果交换被另一个线程争用,则在不更改内存的情况下中止。
        /// </summary>
        /// <remarks>Uses Node.RefineFlag as a lock-keeping mechanism. All refine flags should be cleared to 0 before a multithreaded processing stage that performs swaps.</remarks>
        /// <param name="aIndex">交换对的第一个节点。</param>
        /// <param name="bIndex">交换对的第二个节点。</param>
        /// <return>如果节点已交换,则为True;如果交换已争用,则为False。</return>
        public unsafe bool TrySwapNodesThreadSafe(ref int aIndex, ref int bIndex)
        {
            Debug.Assert(aIndex != bIndex, "Can't swap a node with itself.");

            // 我们必须锁定：
            // 一个
            // B类
            // A->父级
            // B->上级
            // A->{儿童}
            // B->{孩子}
            // 但是要注意节点之间的父辈或祖辈关系。它们降低了所需的锁数量。

            // 请注意,我们不必担心重新排序/死锁,因为这些不是阻塞锁。如果其中一个失败,所有锁将立即中止。
            // 这意味着我们不会总是得到最优的缓存布局,但这根本不会影响正确性。
            // 最终,该节点将被重新访问,并且可能会得到修复。

            // 注意迭代TryLock的使用。它接受这样的事实,即在获取锁之前,可以随时改变参考存储器。
            // 它会进行显式检查,以确保它确实在正确的节点上获取了锁。

            bool success = false;
            if (TryLock(ref aIndex))
            {
                ref var a = ref Metanodes[aIndex];
                if (TryLock(ref bIndex))
                {
                    // 现在,我们知道aIndex和bIndex不会改变。
                    ref var b = ref Metanodes[bIndex];

                    var aParentAvoidedLock = a.Parent == bIndex;
                    if (aParentAvoidedLock || TryLock(ref a.Parent))
                    {
                        var bParentAvoidedLock = b.Parent == aIndex;
                        if (bParentAvoidedLock || TryLock(ref b.Parent))
                        {

                            int aChildrenLockedCount = 2;
                            ref var aChildren = ref Nodes[aIndex].A;
                            for (int i = 0; i < 2; ++i)
                            {
                                ref var child = ref Unsafe.Add(ref aChildren, i);
                                if (child.Index != bIndex && child.Index != b.Parent && !TryLock(ref child.Index))
                                {
                                    // 无法获取对所有子项的锁定。
                                    aChildrenLockedCount = i;
                                    break;
                                }
                            }

                            if (aChildrenLockedCount == 2)
                            {
                                int bChildrenLockedCount = 2;
                                ref var bChildren = ref Nodes[bIndex].A;
                                for (int i = 0; i < 2; ++i)
                                {
                                    ref var child = ref Unsafe.Add(ref bChildren, i);
                                    if (child.Index != aIndex && child.Index != a.Parent && !TryLock(ref child.Index))
                                    {
                                        // 无法获取对所有子项的锁定。
                                        bChildrenLockedCount = i;
                                        break;
                                    }
                                }

                                if (bChildrenLockedCount == 2)
                                {
                                    // 所有节点均已成功锁定。
                                    SwapNodes(aIndex, bIndex);
                                    success = true;
                                }

                                for (int i = bChildrenLockedCount - 1; i >= 0; --i)
                                {
                                    ref var child = ref Unsafe.Add(ref bChildren, i);
                                    if (child.Index != aIndex && child.Index != a.Parent) // 请勿解锁或其父对象。
                                        Metanodes[child.Index].RefineFlag = 0;
                                }
                            }
                            for (int i = aChildrenLockedCount - 1; i >= 0; --i)
                            {
                                ref var child = ref Unsafe.Add(ref aChildren, i);
                                if (child.Index != bIndex && child.Index != b.Parent) // 不要解锁b或其父级。
                                    Metanodes[child.Index].RefineFlag = 0;
                            }
                            if (!bParentAvoidedLock)
                                Metanodes[b.Parent].RefineFlag = 0;
                        }
                        if (!aParentAvoidedLock)
                            Metanodes[a.Parent].RefineFlag = 0;
                    }
                    b.RefineFlag = 0;
                }
                a.RefineFlag = 0;
            }
            return success;
        }


        /// <summary>
        /// 如果指定节点在内存中移动到正确的相对位置,则移动子节点。
        /// 注意避免多线程上下文中的争用移动。可能不会成功
        /// 如果有竞争,请完成所有想要的动作。
        /// </summary>
        /// <param name="nodeIndex">应优化其子项的节点。</param>
        /// <return>如果没有其他线程争用优化或节点已经优化,则为True,否则为False。
        /// 即使并非所有节点都进行了优化,如果原因是目标索引超出节点列表界限,也将返回TRUE。</return>
        public unsafe bool IncrementalCacheOptimizeThreadSafe(int nodeIndex)
        {
            Debug.Assert(leafCount >= 2,
                "Should only use cache optimization when there are at least two leaves. Every node has to have 2 children, and optimizing a 0 or 1 leaf tree is silly anyway.");
            // 多线程缓存优化尝试获取每个相关节点上的锁。
            // 如果任何锁失败,它就会放弃整个尝试。
            // 这是可以接受的-增量优化只关心最终的成功。

            // TODO：如果您知道有问题的树有很多连贯性,可以尝试提前比较没有锁的子指针。
            // 不安全,但可以接受作为优化准备通过。会避免一些连锁反应。似乎对经历任何重大运动的树木没有帮助。
            ref var node = ref Metanodes[nodeIndex];
            bool success = true;

            if (0 == Interlocked.CompareExchange(ref node.RefineFlag, 1, 0))
            {
                ref var children = ref Nodes[nodeIndex].A;
                var targetIndex = nodeIndex + 1;



                // 请注意,我们将所有子节点向上拉到其相对于当前节点索引的最终位置。
                // 这有助于确保更多的节点可以汇聚到它们的最终位置-如果我们没有这样做,
                // 完全自上而下的缓存优化最终可能会将一些节点留在树的底部附近,并且没有任何空间给它们的子节点。
                // TODO：N元树支持。没有子树计数和每个节点没有固定数量的子节点很麻烦,但这是可能的
                // 仍然选择一些汇聚在一起的东西。

                for (int i = 0; i < 2; ++i)
                {
                    ref var child = ref Unsafe.Add(ref children, i);
                    if (targetIndex >= nodeCount)
                    {
                        // 此尝试的交换将超出分配的节点。
                        // 这意味着当前节点比其应有的值要低得多。
                        // 以后的改进尝试应该会解决这个问题,但目前什么都不做。
                        // 其他选项：
                        // 我们可以积极向上交换这个节点。更复杂。
                        break;
                    }
                    // 该子指针很有可能在现在和比较交换读取之间进行交换。
                    // 但是,子指针不会从内部节点(正)变成叶节点(负),这才是最重要的。
                    if (child.Index >= 0)
                    {
                        // 在比较孩子之前锁定,以防止孩子换衣服。
                        if (TryLock(ref child.Index))
                        {
                            // 虽然我们在早些时候检查了Child[i]！=targetIndex是否提前退出,但必须在锁定后进行,以确保正确性,因为Child[i]可能已经更改了。
                            // 尝试在索引和其本身之间进行交换是无效的。
                            if (child.Index != targetIndex)
                            {
                                // 现在把这个孩子的孩子都锁起来。
                                ref var childNode = ref Nodes[child.Index];
                                ref var grandchildren = ref childNode.A;
                                int lockedChildrenCount = 2;
                                for (int grandchildIndex = 0; grandchildIndex < 2; ++grandchildIndex)
                                {
                                    ref var grandchild = ref Unsafe.Add(ref grandchildren, grandchildIndex);
                                    // 这个孙子指针很有可能在现在和比较交换读取之间进行交换。
                                    // 但是,子指针不会从内部节点(正)变成叶节点(负),这才是最重要的。
                                    if (grandchild.Index >= 0 && !TryLock(ref grandchild.Index))
                                    {
                                        lockedChildrenCount = grandchildIndex;
                                        break;
                                    }
                                }
                                if (lockedChildrenCount == 2)
                                {
                                    Debug.Assert(node.RefineFlag == 1);
                                    if (!TrySwapNodeWithTargetThreadSafe(child.Index, nodeIndex, targetIndex))
                                    {
                                        // 目标锁定失败。
                                        success = false;
                                    }
                                    Debug.Assert(node.RefineFlag == 1);

                                }
                                else
                                {
                                    // 孙子锁失败。
                                    success = false;
                                }

                                // 解锁所有孙子。
                                // 请注意,我们不能使用老孙指针。如果交换成功了,那就是指向*目标的*孩子。
                                // 所以更新指针。
                                grandchildren = ref Nodes[child.Index].A;
                                for (int grandchildIndex = lockedChildrenCount - 1; grandchildIndex >= 0; --grandchildIndex)
                                {
                                    ref var grandchild = ref Unsafe.Add(ref grandchildren, grandchildIndex);
                                    if (grandchild.Index >= 0)
                                        Metanodes[grandchild.Index].RefineFlag = 0;
                                }

                            }
                            // 解锁。如果掉期交易成功,那么Child[i]就是targetIndex,如果没有,它就是原始子指数。
                            // 这些都是合适的目标。
                            Metanodes[child.Index].RefineFlag = 0;
                        }
                        else
                        {
                            // 失败的子锁。
                            success = false;
                        }
                        // 叶数不能因其他线程而更改。
                        targetIndex += child.LeafCount - 1; // 仅适用于2元树。
                    }
                }
                // 解锁父项。
                node.RefineFlag = 0;
            }
            else
            {
                // 父锁失败。
                success = false;
            }
            return success;
        }

        public unsafe void IncrementalCacheOptimize(int nodeIndex)
        {
            if (leafCount <= 2)
            {
                // 如果只有两个叶子,则不必费心进行缓存优化。无事可做,为睡觉的优化逻辑提供了保障
                // 这样我们就不必检查每个节点的子节点计数。
                return;
            }

            ref var node = ref Nodes[nodeIndex];
            ref var children = ref node.A;
            var targetIndex = nodeIndex + 1;

            // 请注意,我们将所有子节点向上拉到其相对于当前节点索引的最终位置。
            // 这有助于确保更多的节点可以汇聚到它们的最终位置-如果我们没有这样做,
            // 完全自上而下的缓存优化最终可能会将一些节点留在树的底部附近,并且没有任何空间给它们的子节点。
            // TODO：N元树支持。没有子树计数和每个节点没有固定数量的子节点很麻烦,但这是可能的
            // 仍然选择一些汇聚在一起的东西。

            for (int i = 0; i < 2; ++i)
            {
                if (targetIndex >= nodeCount)
                {
                    // 此尝试的交换将超出分配的节点。
                    // 这意味着当前节点比其应有的值要低得多。
                    // 以后的改进尝试应该会解决这个问题,但目前什么都不做。
                    // 其他选项：
                    // 我们可以积极向上交换这个节点。更复杂。
                    break;
                }
                ref var child = ref Unsafe.Add(ref children, i);
                if (child.Index >= 0)
                {
                    if (child.Index != targetIndex)
                    {
                        SwapNodes(child.Index, targetIndex);
                    }
                    // 断线;
                    targetIndex += child.LeafCount - 1;
                }
            }
        }



        unsafe void CacheOptimize(int nodeIndex, ref int nextIndex)
        {
            ref var node = ref Nodes[nodeIndex];
            ref var children = ref node.A;
            for (int i = 0; i < 2; ++i)
            {
                ref var child = ref Unsafe.Add(ref children, i);
                if (child.Index >= 0)
                {
                    Debug.Assert(nextIndex >= 0 && nextIndex < nodeCount,
                        "Swap target should be within the node set. If it's not, the initial node was probably not in global optimum position.");
                    if (child.Index != nextIndex)
                        SwapNodes(child.Index, nextIndex);
                    Debug.Assert(child.Index != nextIndex);
                    ++nextIndex;
                    CacheOptimize(child.Index, ref nextIndex);
                }
            }
        }


        /// <summary>
        /// 从给定节点开始缓存优化,并一直进行到树的底部。
        /// 要求目标节点已经处于全局最优位置。
        /// </summary>
        /// <param name="nodeIndex">开始优化过程的节点。</param>
        public unsafe void CacheOptimize(int nodeIndex)
        {
            if (leafCount <= 2)
            {
                // 如果只有两个叶子,则不必费心进行缓存优化。无事可做,为睡觉的优化逻辑提供了保障
                // 这样我们就不必检查每个节点的子节点计数。
                return;
            }
            var targetIndex = nodeIndex + 1;

            CacheOptimize(nodeIndex, ref targetIndex);
        }
    }

}
